package org.muninn.niagara.structures;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;

import javax.baja.bacnet.datatypes.BBacnetUnsigned;
import javax.baja.bacnet.virtual.BBacnetVirtualProperty;
import javax.baja.control.BBooleanWritable;
import javax.baja.control.BEnumWritable;
import javax.baja.control.BNumericWritable;
import javax.baja.fox.BFoxProxySession;
import javax.baja.naming.BHost;
import javax.baja.naming.BOrd;
import javax.baja.naming.UnresolvedException;
import javax.baja.status.BStatusBoolean;
import javax.baja.status.BStatusNumeric;
import javax.baja.sys.BBoolean;
import javax.baja.sys.BComponent;
import javax.baja.sys.BDouble;
import javax.baja.sys.BDynamicEnum;
import javax.baja.sys.BInteger;
import javax.baja.sys.BObject;
import javax.baja.sys.Sys;
import javax.baja.sys.Type;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * 
 * Data structure to represent a system of JACEs and perform functions on that system. Reads data from an <code>XML</code> file.
 * Tree consists of four levels:
 * <ul>
 * <li>First level (<code>IP</code>): contains the array of <code>IP</code> objects containing the second level, the build method for the first level objects,
 *     and methods for starting sessions and exporting logs.
 * <li>Second level (<code>Controller</code>): contains the array of <code>Controller</code> objects containing the third level, the build method for the
 *     second level objects, and methods for starting a session and executing modes by <code>IP</code> or <code>Controller</code>.
 * <li>Third level (<code>Point</code>): contains the array of <code>Point</code> objects containing the fourth level, the build method for the third level
 *     objects, and methods for executing modes by name/index or by <code>Point</code>.
 * <li>Fourth level (<code>Mode</code>): contains the array of <code>Mode</code> objects, the build method for the the fourth level objects, and methods for
 *     executing modes by name or number.
 * </ul>
 * 
 * <p><code>XML</code> file must be of the form:<br>
 * <code>
 * &lt;root&gt;<br>
 * &nbsp;&lt;ip address = "[address]" uname = "[username]" pword = "[password]" port = "[port]"&gt;<br>
 * &nbsp;&nbsp;&lt;controller name = "[name]" ord = "[ord]"&gt;<br>
 * &nbsp;&nbsp;&nbsp;&lt;point name = "[name]" type = "[numeric/boolean/virtual]"&gt;<br>
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;mode name = "[name]" type = "[numeric/boolean/virtual]" number = "[number]"&gt;int/boolean&lt;/mode&gt;<br>
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;mode name = "[name]" type = "[numeric/boolean/virtual]" number = "[number]"&gt;int/boolean&lt;/mode&gt;<br>
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;mode name = "[name]" type = "[numeric/boolean/virtual]" number = "[number]"&gt;int/boolean&lt;/mode&gt;<br>
 * &nbsp;&nbsp;&nbsp;&lt;/point&gt;<br>
 * &nbsp;&nbsp;&lt;/controller&gt;<br>
 * &nbsp;&lt;/ip&gt;<br>
 * &lt;/root&gt;<br>
 * </code>
 * 
 * <p>Operating in verbose mode causes all actions to be printed and pushed onto a stack. When <code>makeLog</code> is called, all items on the stack are popped
 * off and written to a .txt file named with the time of the method call in the specified directory. The title is of the form <code>month_day_hour_minute_second.txt</code>.
 *
 * @author Conor Freeland, Muninn Group
 * @creation Jan 2013
 *
 */
public class BJaceTree extends BObject
{
  public IP[] stations;
  private BFoxProxySession currSession = null;
  private boolean success = false;
  private boolean verbosity;
  private BStack outStack;
  
  /**
   * Constructor for when verbose mode is never used.
   * @param file            path to the XML file containing build data for the tree
   */
  public BJaceTree(String file) { new BJaceTree(file, false); }
  
  /**
   * Main constructor
   * @param file            path to the XML file containing build data for the tree
   * @param errFolder       directory in which to store the log file
   * @param verbose         boolean to determine whether or not to run in verbose mode
   */
  public BJaceTree(String file, boolean verbose)
  {
    Document doc;
    verbosity = verbose;
    if (verbosity)
      outStack = new BStack();

    try
    {
      if (verbosity) pushPrint("Building tree...\n");
      DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
      doc = builder.parse(file);
      success = build(doc);
      if (verbosity && !success) pushPrint("***Failed to build tree\n");
    }
    catch (ParserConfigurationException e) { if (verbosity) pushPrint("***Parser exception:\n" + e.toString() + "\n"); }
    catch (SAXException f) { if (verbosity) pushPrint("***XML exception:\n" + f.toString() + "\n"); }
    catch (IOException g) { if (verbosity) pushPrint("***IO exception:\n" + g.toString() + "\n"); }
  }
  
  /**
   * Build method for the top level of the tree.
   * @param doc             <code>Document</code> object representing the XML file containing build data for the tree
   * @return                true/false depending on success/failure
   */
  private boolean build(Document doc)
  {
    NodeList list = doc.getDocumentElement().getElementsByTagName("ip");
    stations = new IP[list.getLength()];

    if (list != null && list.getLength() != 0)
    {
      for (int i = 0; i < list.getLength(); i++)
      {
        IP ip = new IP(((Element) list.item(i)).getAttribute("address"),
                       ((Element) list.item(i)).getAttribute("uname"),
                       ((Element) list.item(i)).getAttribute("pword"),
                       ((Element) list.item(i)).getAttribute("port"));
        if (verbosity) pushPrint(" Building IP...\n");
        ip.build((Element) list.item(i));
        stations[i] = ip;      
        if (verbosity) pushPrint(" Built IP: " + ip.address + "\n");
      }

      if (verbosity) pushPrint("Built tree\n");
      return true;
    }

    else
    {
      if (verbosity) pushPrint("***No IPs found\n");
      return false;
    }
  }
  
  /**
   * Calls the <code>startSessionOnIP(IP)</code> method with the <code>IP</code> represented by the parameter.
   * @param index           index of the <code>IP</code> of interest in the <code>stations</code> array
   * @return                return value of the <code>startSessionOnIP</code> method
   */
  public boolean startSessionOnIP(int index) { return startSessionOnIP(getIP(index)); }
  
  /**
   * Calls the <code>startSessionOnIP(IP)</code> method with the <code>IP</code> represented by the parameter.
   * @param address         address of the <code>IP</code> of interest
   * @return                return value of the <code>startSessionOnIP(IP)</code> method
   */
  public boolean startSessionOnIP(String address) { return startSessionOnIP(getIP(address)); }
  
  /**
   * Calls the <code>startSession</code> method of the <code>IP</code>
   * @param ip               <code>IP</code> to be used
   * @return                 return value of the <code>startSessionOnIP</code> method
   */
  private boolean startSessionOnIP(IP ip) { return ip.startSession(); }
  
  /**
   * If <code>currSession</code> is active, disengage it.
   */
  public void stopCurrentSession()
  {
    if (currSession != null && currSession.isEngaged("session"))
      currSession.disengage("session");
  }
  
  /**
   * Get the currently active station. If <code>currStation</code> is null, disconnected, or not running, use the local station.
   * @return                  working station, with remote stations given precedence over the local station
   */
  public boolean isRemote()
  {
    if (currSession != null && currSession.isConnected())
      return true;
    else
      return false;
  }
  
  /**
   * Finds an <code>IP</code> by its <code>address</code> property.
   * @param address           IP address as a string
   * @return                  <code>IP</code> if a match is found, <code>null</code> otherwise
   */
  public IP getIP(String address)
  {
    for (int i = 0; i < this.size(); i++)
    {
      if (stations[i].address.equals(address))
        return stations[i];
    }
    if (verbosity) pushPrint("***No such IP: " + address + "\n");
    return null;
  }
  
  /**
   * Finds an <code>IP</code> by its index in the <code>stations</code> array.
   * @param index             index of the <code>IP</code> of interest
   * @return                  <code>IP</code> if index is valid, <code>null</code> otherwise
   */
  public IP getIP(int index)
  {
    if (index >= 0 && index < this.size())
      return stations[index];
    else
    {
      if (verbosity) pushPrint("***Index " + index + " not in range\n");
      return null;
    }
  }
  
  /**
   * Prints messages before pushing them to <code>outStack</code>.
   * @param string            message to be printed before being pushed to the stack
   */
  public void pushPrint(String string)
  {
    Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("EST"));
    String hour, min, sec, milli;

    System.out.println(string);

    hour = Integer.toString(calendar.get(Calendar.HOUR));    
    min = Integer.toString(calendar.get(Calendar.MINUTE));    
    sec = Integer.toString(calendar.get(Calendar.SECOND));    
    milli = Integer.toString(calendar.get(Calendar.MILLISECOND));

    if (hour.length() < 2)
      hour = "0" + hour;

    if (min.length() < 2)
      min = "0" + min;

    if (sec.length() < 2)
      sec = "0" + sec;

    while (milli.length() < 3)
      milli = "0" + milli;

    outStack.push(hour + ":" +
        min + ":" +
        sec + "." +
        milli + "   " + string);
  }
  
  /**
   * Prints contents of <code>outStack</code> to a file.
   * @param folder            path to the directory for the log file
   * @throws IOException      if an exception occurs while opening or writing to the file
   */
  public String makeLog(String folder) throws IOException
  {
    if (verbosity)
    {
      Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("EST"));
      String stream = "";
      String title = folder + calendar.get(GregorianCalendar.MONTH) + "_" +
          calendar.get(Calendar.DAY_OF_MONTH) + "_" +
          calendar.get(Calendar.HOUR_OF_DAY) + "_" +
          calendar.get(Calendar.MINUTE) + ".txt";
      File log = new File(title);
      File vlog = new File(folder + "log.html");
      try
      {
        PrintWriter outStream = new PrintWriter(log);
        PrintWriter voutStream = new PrintWriter(vlog);

        voutStream.append("<html><body>");

        while (!(outStack.isEmpty()))
        {
          String temp = outStack.pop();
          if (temp.indexOf("*") != -1)
          {
            stream = temp + stream;
            voutStream.append("<font color=red>" + temp + "</font><br>");
          }
          else
            voutStream.append(temp + "<br>");

          outStream.append(temp);
        }

        voutStream.append("</body></html>");

        voutStream.close();
        outStream.close();
        return stream;
      }
      catch (IOException e)
      {
        System.out.println(e.toString());
        return null;
      }
    }
    else
      return null;
  }
  
  /**
   * Get the size of the second level of the tree
   * @return                  <code>length</code> property of the <code>stations</code> array
   */
  public int size() { return stations.length; }
  
  /**
   * Determines whether or not the tree was successfully constructed
   * @return                  boolean set by the return value of the top-level <code>build</code> method
   */
  public boolean isBuilt() { return success; }
  
  //*********************************************************************************************************************************************************************************
  //******************************************************************************************************************************************************************************IP*
  //*********************************************************************************************************************************************************************************
  /**
   * 
   * Object representing a first level node of the <code>BJaceTree</code>. Contains an array of second level objects and methods for starting a session and
   * executing modes by <code>IP</code> or <code>Controller</code>.
   *
   * @author Conor Freeland, Muninn Group
   * @creation Jan 2013
   *
   */
  public class IP
  {
    public String address = null;
    public String uName = null;
    public String pWord = null;
    public int port = 0;
    public Controller[] controllers;
    
    /**
     * Constructor for the class.
     * @param address         IP address
     * @param uname           username for the station
     * @param pword           password corresponding to the username
     * @param port            port on which the server runs
     */
    public IP(String address, String uname, String pword, String port)
    {
      this.address = address;
      this.port = Integer.parseInt(port);
      uName = uname;
      pWord = pword;
    }
    
    /**
     * Build method for the second level of the tree.
     * @param ip              <code>Element</code> containing build data for the lower levels of the tree
     */
    private void build(Element ip)
    {
      NodeList list = ip.getElementsByTagName("controller");
      controllers = new Controller[list.getLength()];

      if (list != null && list.getLength() != 0)
      {
        for (int i = 0; i < list.getLength(); i++)
        {
          Controller cont = new Controller(((Element) list.item(i)).getAttribute("name"),
                                           ((Element) list.item(i)).getAttribute("ord"));
          if (verbosity) pushPrint("  Building controller...\n");
          cont.build((Element) list.item(i));
          controllers[i] = cont;
          if (verbosity) pushPrint("  Built controller: " + cont.cName + "\n");
        }
      }

      else
        if (verbosity) pushPrint("***No controllers found\n");
    }
    
    /**
     * Attempts to engage a session and connect to a station based on the <code>address</code> and <code>port</code> values of <code>this</code>.
     * @return                true/false based on success/failure of the attempted connections
     */
    public boolean startSession()
    {
      if (address.equals(Sys.getLocalHost().getHostAddress()) || address.equals("local"))
      {
        if (verbosity) pushPrint("Engaged local session: " + address + "\n");
        return true;
      }

      else
      {
        if (currSession != null && currSession.isEngaged("session"))
          stopCurrentSession();

        currSession = BFoxProxySession.make((BHost) BOrd.make("ip:" + address).get(), port, uName, pWord);
        try
        {
          currSession.engageNoRetry("session");

          if (currSession.isEngaged("session"))
          {
            if (verbosity) pushPrint("Engaged session on " + address + "\n");
            return true;
          }

          else
          {
            if (verbosity) pushPrint("***Failed to engage session on " + address + "\n");
            return false;
          }
        }
        catch (Exception e)
        {
          if (verbosity) pushPrint("***Bad IP address:\n" + e.toString() + "\n");
          return false;
        }
      }
    }
    
    /**
     * Executes all <code>Modes</code> in a particular position in their respective arrays.
     * @param index           index of all <code>Modes</code> to execute
     * @return                aggregate return values of all calls to <code>executeModesOnCont</code>
     */
    public boolean executeModes(int index)
    {
      boolean success = true;
      for (int i = 0; i < this.size(); i++)
        success = executeModesOnCont(index, i) && success;
      return success;
    }
    
    /**
     * Executes all <code>Modes</code> whose <code>mName</code> property matches the parameter
     * @param name            name of all <code>Modes</code> to execute
     * @return                aggregate return values of all calls to <code>executeModesOnCont</code>
     */
    public boolean executeModes(String name)
    {
      boolean success = true;
      for (int i = 0; i < this.size(); i++)
        success = executeModesOnCont(name, i) && success;
      return success;
    }
    
    /**
     * Calls the <code>executeModesOnCont(int, Controller)</code> method with the <code>Controller</code> represented by the second parameter.
     * @param mIndex          index of all <code>Modes</code> to execute
     * @param cIndex          index of the <code>Controller</code> on which to execute <code>Modes</code>
     * @return                return value of the <code>executeModesOnCont(int, Controller)</code> method
     */
    public boolean executeModesOnCont(int mIndex, int cIndex) { return executeModesOnCont(mIndex, getController(cIndex)); }
    
    /**
     * Calls the <code>executeModesOnCont(int, Controller)</code> method with the <code>Controller</code> represented by the second parameter.
     * @param mIndex          index of all <code>Modes</code> to execute
     * @param cName           name of the <code>Controller</code> on which to execute <code>Modes</code>
     * @return                return value of the <code>executeModesOnCont(int, Controller)</code> method
     */
    public boolean executeModesOnCont(int mIndex, String cName) { return executeModesOnCont(mIndex, getController(cName)); }
    
    /**
     * Calls the <code>executeModesOnCont(String, Controller)</code> method with the <code>Controller</code> represented by the second parameter.
     * @param mName           name of all <code>Modes</code> to execute
     * @param cIndex          index of the <code>Controller</code> on which to execute <code>Modes</code>
     * @return                return value of the <code>executeModesOnCont(String, Controller)</code> method
     */
    public boolean executeModesOnCont(String mName, int cIndex) { return executeModesOnCont(mName, getController(cIndex)); }
    
    /**
     * Calls the <code>executeModesOnCont(String, Controller)</code> method with the <code>Controller</code> represented by the second parameter.
     * @param mName           name of all <code>Modes</code> to execute
     * @param cName           name of the <code>Controller</code> on which to execute <code>Modes</code>
     * @return                return value of the <code>executeModesOnCont(String, Controller)</code> method
     */
    public boolean executeModesOnCont(String mName, String cName) { return executeModesOnCont(mName, getController(cName)); }
    
    /**
     * Calls the <mode>executeModes(int)</code> of the <code>Controller</code> passed as a parameter.
     * @param mIndex          index of all <code>Modes</code> to execute
     * @param cont            <code>Controller</code> on which to execute <code>Modes</code>
     * @return                return value of the <code>executeModes</code> method
     */
    private boolean executeModesOnCont(int mIndex, Controller cont) { return cont.executeModes(mIndex); }
    
    /**
     * Calls the <mode>executeModes(String)</code> of the <code>Controller</code> passed as a parameter.
     * @param mName           name of all <code>Modes</code> to execute
     * @param cont            <code>Controller</code> on which to execute <code>Modes</code>
     * @return                return value of the <code>executeModes</code> method
     */
    private boolean executeModesOnCont(String mName, Controller cont) { return cont.executeModes(mName); }
    
    /**
     * Checks against all <code>Modes</code> in a particular position in their respective arrays.
     * @param index           index of all <code>Modes</code> to be checked against
     * @return                aggregate return values of all calls to <code>checkModesOnCont</code>
     */
    public boolean checkModes(int index)
    {
      boolean success = true;
      for (int i = 0; i < this.size(); i++)
        success = checkModesOnCont(index, i) && success;
      return success;
    }
    
    /**
     * Checks against all <code>Modes</code> in a particular position in their respective arrays.
     * @param name            name of all <code>Modes</code> to be checked against
     * @return                aggregate return values of all calls to <code>checkModesOnCont</code>
     */
    public boolean checkModes(String name)
    {
      boolean success = true;
      for (int i = 0; i < this.size(); i++)
        success = checkModesOnCont(name, i) && success;
      return success;
    }
    
    /**
     * Calls the <code>checkModesOnCont(int, Controller)</code> method with the <code>Controller</code> represented by the second parameter.
     * @param mIndex          index of all <code>Modes</code> to be checked against
     * @param cIndex          index of the <code>Controller</code> on which to check against <code>Modes</code>
     * @return                return value of the <code>checkModesOnCont(int, Controller)</code> method
     */
    public boolean checkModesOnCont(int mIndex, int cIndex) { return checkModesOnCont(mIndex, getController(cIndex)); }
    
    /**
     * Calls the <code>checkModesOnCont(int, Controller)</code> method with the <code>Controller</code> represented by the second parameter.
     * @param mIndex          index of all <code>Modes</code> to be checked against
     * @param cName           name of the <code>Controller</code> on which to check against <code>Modes</code>
     * @return                return value of the <code>checkModesOnCont(int, Controller)</code> method
     */
    public boolean checkModesOnCont(int mIndex, String cName) { return checkModesOnCont(mIndex, getController(cName)); }
    
    /**
     * Calls the <code>checkModesOnCont(int, Controller)</code> method with the <code>Controller</code> represented by the second parameter.
     * @param mName           name of all <code>Modes</code> to be checked against
     * @param cIndex          index of the <code>Controller</code> on which to check against <code>Modes</code>
     * @return                return value of the <code>checkModesOnCont(int, Controller)</code> method
     */
    public boolean checkModesOnCont(String mName, int cIndex) { return checkModesOnCont(mName, getController(cIndex)); }
    
    /**
     * Calls the <code>checkModesOnCont(int, Controller)</code> method with the <code>Controller</code> represented by the second parameter.
     * @param mName           name of all <code>Modes</code> to be checked against
     * @param cName           name of the <code>Controller</code> on which to check against <code>Modes</code>
     * @return                return value of the <code>checkModesOnCont(int, Controller)</code> method
     */
    public boolean checkModesOnCont(String mName, String cName) { return checkModesOnCont(mName, getController(cName)); }
    
    /**
     * Calls the <mode>checkModes(int)</code> of the <code>Controller</code> passed as a parameter.
     * @param mIndex          index of all <code>Modes</code> to be checked against
     * @param cont            <code>Controller</code> on which to check against <code>Modes</code>
     * @return                return value of the <code>checkModes</code> method
     */
    private boolean checkModesOnCont(int mIndex, Controller cont) { return cont.checkModes(mIndex); }
    
    /**
     * Calls the <mode>checkModes(String)</code> of the <code>Controller</code> passed as a parameter.
     * @param mName           name of all <code>Modes</code> to be checked against
     * @param cont            <code>Controller</code> on which to check against <code>Modes</code>
     * @return                return value of the <code>checkModes</code> method
     */
    private boolean checkModesOnCont(String mName, Controller cont) { return cont.checkModes(mName); }
    
    public String createModeOnPoints(String type, String value)
    {
      String temp = null;
      for (int i = 0; i < this.size(); i++)
        temp = getController(i).createModeOnPoints(type, value);
      return temp;
    }
    
    /**
     * Finds a <code>Controller</code> by its <code>cName</code> property.
     * @param name            name of the <code>Controller</code> of interest
     * @return                <code>Controller</code> if a match is found, <code>null</code> otherwise
     */
    public Controller getController(String name)
    {
      for (int i = 0; i < this.size(); i++)
      {
        if (controllers[i].cName.equals(name))
          return controllers[i];
      }
      if (verbosity) pushPrint("***No such controller: " + name + "\n");
      return null;
    }
    
    /**
     * Finds a <code>Controller</code> by its index in the <code>controllers</code> array.
     * @param index           index of the <code>Controller</code> of interest
     * @return                <code>Controller</code> if index is valid, <code>null</code> otherwise
     */
    public Controller getController(int index)
    {
      if (index >= 0 && index < this.size())
        return controllers[index];
      else
      {
        if (verbosity) pushPrint("***Index " + index + " not in range\n");
        return null;
      }
    }
    
    /**
     * Get the size of the third level of the tree
     * @return                <code>length</code> property of the <code>controllers</code> array
     */
    public int size() { return controllers.length; }
    
    //*******************************************************************************************************************************************************************************
    //********************************************************************************************************************************************************************Controller*
    //*******************************************************************************************************************************************************************************
    /**
     * 
     * Object representing a second level node of the <code>BJaceTree</code>. Contains an array of third level objects and methods for executing modes by
     * name/index or by <code>Point</code>.
     *
     * @author Conor Freeland, Muninn Group
     * @creation Jan 2013
     *
     */
    public class Controller
    {
      public String cName = null;
      public String ord = null;
      public Point[] points;
      
      /**
       * Constructor for the class.
       * @param name          name of the physical controller
       * @param ord           ORD pointing to the software representation of the controller
       */
      public Controller(String name, String ord)
      {
        this.cName = name;
        this.ord = ord;
      }
      
      /**
       * Build method for the third level of the tree.
       * @param cont          <code>Element</code> containing build data for the lower levels of the tree
       */
      private void build(Element cont)
      {
        NodeList list = cont.getElementsByTagName("point");
        points = new Point[list.getLength()];

        if (list != null && list.getLength() != 0)
        {
          for (int i = 0; i < list.getLength(); i++)
          {
            Point point = new Point(((Element) list.item(i)).getAttribute("name"),
                                    ((Element) list.item(i)).getAttribute("type"), ord);
            if (verbosity) pushPrint("   Creating point...\n");
            point.build((Element) list.item(i));

            if (point.type.equals("numeric") || point.type.equals("boolean") || point.type.equals("enum") || point.type.equals("virtual"))
            {
              points[i] = point;
              if (verbosity)
                pushPrint("   Created point: " + point.pName + "\n");
            }

            else
            {
              if (verbosity)
                pushPrint("***Could not add " + point.type + " point " + cName + "/" + point.pName + ": invalid point type\n");
            }
          }
        }
      }
      
      /**
       * Calls the <code>resolve(Point)</code> method with the <code>Point</code> object specified by the parameter.
       * @param name          index of the point to be resolved
       * @return              return value of <code>resolve(Point)</code>, or <code>null</code> if no such point exists
       */
      public BComponent resolve(int index)
      {
        if (getPoint(index) != null)
          return resolve(getPoint(index));
        else
          return null;
      }
      
      /**
       * Calls the <code>resolve(Point)</code> method with the <code>Point</code> object specified by the parameter.
       * @param name          name of the point to be resolved
       * @return              return value of <code>resolve(Point)</code>, or <code>null</code> if no such point exists
       */
      public BComponent resolve(String name)
      {
        if (getPoint(name) != null)
          return resolve(getPoint(name));
        else
          return null;
      }
      
      /**
       * Resolves the desired point to a <code>BComponent</code>
       * @param point         <code>Point</code> object to be resolved
       * @return              <code>BComponent</code> resulting from starting the point
       */
      private BComponent resolve(Point point) { return point.startPoint(); }
      
      /**
       * Calls the <code>executeModeOnPoint(int, int)</code> method for all modes of the index given by the parameter.
       * @param index         index of all <code>Modes</code> to be executed
       * @return              aggregate return values of all calls to <code>executeModeOnPoint(int, int)</code>
       */
      public boolean executeModes(int index)
      {
        boolean success = true;
        for (int i = 0; i < this.size(); i++)
          success = executeModeOnPoint(index, i) && success;
        return success;
      }
      
      /**
       * Calls the <code>executeModeOnPoint(String, int)</code> method for all modes of the name given by the parameter.
       * @param name          name of all <code>Modes</code> to be executed
       * @return              aggregate return values of all calls to <code>executeModeOnPoint(String, int)</code>
       */
      public boolean executeModes(String name)
      {
        boolean success = true;
        for (int i = 0; i < this.size(); i++)
          success = executeModeOnPoint(name, i) && success;
        return success;
      }
      
      /**
       * Calls the <code>executeModeOnPoint(int, Point)</code> method with the <code>Point</code> represented by the second parameter.
       * @param mIndex        index of all <code>Modes</code> to execute
       * @param pIndex        index of the <code>Point</code> on which to execute <code>Modes</code>
       * @return              return value of the <code>executeModeOnPoint(int, Point)</code> method
       */
      public boolean executeModeOnPoint(int mIndex, int pIndex) { return executeModeOnPoint(mIndex, getPoint(pIndex)); }
      
      /**
       * Calls the <code>executeModeOnPoint(String, Point)</code> method with the <code>Point</code> represented by the second parameter.
       * @param mName         index of all <code>Modes</code> to execute
       * @param pIndex        index of the <code>Point</code> on which to execute <code>Modes</code>
       * @return              return value of the <code>executeModeOnPoint(String, Point)</code> method
       */
      public boolean executeModeOnPoint(String mName, int pIndex) { return executeModeOnPoint(mName, getPoint(pIndex)); }
      
      /**
       * Calls the <code>executeModeOnPoint(int, Point)</code> method with the <code>Point</code> represented by the second parameter.
       * @param mIndex        index of all <code>Modes</code> to execute
       * @param pName         name of the <code>Point</code> on which to execute <code>Modes</code>
       * @return              return value of the <code>executeModeOnPoint(int, Point)</code> method
       */
      public boolean executeModeOnPoint(int mIndex, String pName) { return executeModeOnPoint(mIndex, getPoint(pName)); }
      
      /**
       * Calls the <code>executeModeOnPoint(String, Point)</code> method with the <code>Point</code> represented by the second parameter.
       * @param mName         name of all <code>Modes</code> to execute
       * @param pName         name of the <code>Point</code> on which to execute <code>Modes</code>
       * @return              return value of the <code>executeModeOnPoint(String, Point)</code> method
       */
      public boolean executeModeOnPoint(String pName, String mName) { return executeModeOnPoint(mName, getPoint(pName)); }
      
      /**
       * Calls the <mode>executeMode(int)</code> of the <code>Point</code> passed as a parameter.
       * @param mIndex        index of the <code>Mode</code> to execute
       * @param point         <code>Point</code> on which to execute the <code>Mode</code>
       * @return              return value of the <code>executeModes</code> method
       */
      private boolean executeModeOnPoint(int mIndex, Point point) { return point.executeMode(mIndex); }
      
      /**
       * Calls the <mode>executeMode(String)</code> of the <code>Point</code> passed as a parameter.
       * @param mName         name of the <code>Mode</code> to execute
       * @param point         <code>Point</code> on which to execute the <code>Mode</code>
       * @return              return value of the <code>executeModes</code> method
       */
      private boolean executeModeOnPoint(String mName, Point point) { return point.executeMode(mName); }
      
      /**
       * Calls the <code>checkModeOnPoint(int, int)</code> method for all modes of the index given by the parameter.
       * @param index         index of all <code>Modes</code> to be checked against
       * @return              aggregate return values of all calls to <code>checkModeOnPoint(int, int)</code>
       */
      public boolean checkModes(int index)
      {
        boolean success = true;
        for (int i = 0; i < this.size(); i++)
          success = checkModeOnPoint(index, i) && success;
        return success;
      }
      
      /**
       * Calls the <code>checkModeOnPoint(String, int)</code> method for all modes of the name given by the parameter.
       * @param name          name of all <code>Modes</code> to be checked against
       * @return              aggregate return values of all calls to <code>executeModeOnPoint(String, int)</code>
       */
      public boolean checkModes(String name)
      {
        boolean success = true;
        for (int i = 0; i < this.size(); i++)
          success = checkModeOnPoint(name, i) && success;
        return success;
      }
      
      /**
       * Calls the <code>checkModeOnPoint(int, Point)</code> method with the <code>Point</code> represented by the second parameter.
       * @param mIndex        index of all <code>Modes</code> to be checked against
       * @param pIndex        index of the <code>Point</code> to check against <code>Modes</code>
       * @return              return value of the <code>checkModeOnPoint(int, Point)</code> method
       */
      public boolean checkModeOnPoint(int mIndex, int pIndex) { return checkModeOnPoint(mIndex, getPoint(pIndex)); }
      
      /**
       * Calls the <code>checkModeOnPoint(int, Point)</code> method with the <code>Point</code> represented by the second parameter.
       * @param mName         name of all <code>Modes</code> to be checked against
       * @param pIndex        index of the <code>Point</code> to check against <code>Modes</code>
       * @return              return value of the <code>checkModeOnPoint(int, Point)</code> method
       */
      public boolean checkModeOnPoint(String mName, int pIndex) { return checkModeOnPoint(mName, getPoint(pIndex)); }
      
      /**
       * Calls the <code>checkModeOnPoint(int, Point)</code> method with the <code>Point</code> represented by the second parameter.
       * @param mIndex        index of all <code>Modes</code> to be checked against
       * @param pName         name of the <code>Point</code> to check against <code>Modes</code>
       * @return              return value of the <code>checkModeOnPoint(int, Point)</code> method
       */
      public boolean checkModeOnPoint(int mIndex, String pName) { return checkModeOnPoint(mIndex, getPoint(pName)); }
      
      /**
       * Calls the <code>checkModeOnPoint(int, Point)</code> method with the <code>Point</code> represented by the second parameter.
       * @param mName         name of all <code>Modes</code> to be checked against
       * @param pName         name of the <code>Point</code> to check against <code>Modes</code>
       * @return              return value of the <code>checkModeOnPoint(int, Point)</code> method
       */
      public boolean checkModeOnPoint(String mName, String pName) { return checkModeOnPoint(mName, getPoint(pName)); }
      
      /**
       * Calls the <mode>checkPoint(int)</code> of the <code>Point</code> passed as a parameter.
       * @param mName         index of the <code>Mode</code> to be checked against
       * @param point         <code>Point</code> to check against the <code>Mode</code>
       * @return              return value of the <code>checkPoint</code> method
       */
      private boolean checkModeOnPoint(int mIndex, Point point) { return point.checkPoint(mIndex); }
      
      /**
       * Calls the <mode>checkPoint(String)</code> of the <code>Point</code> passed as a parameter.
       * @param mName         name of the <code>Mode</code> to be checked against
       * @param point         <code>Point</code> to check against the <code>Mode</code>
       * @return              return value of the <code>checkPoint</code> method
       */
      private boolean checkModeOnPoint(String mName, Point point) { return point.checkPoint(mName); }
      
      public String createModeOnPoints(String type, String value)
      {
        String temp = null;
        for (int i = 0; i < this.size(); i++)
          temp = getPoint(i).createMode(type, value);
        return temp;
      }
      
      /**
       * Finds a <code>Point</code> by its <code>pName</code> property.
       * @param name          name of the <code>Point</code> of interest
       * @return              <code>Point</code> if a match is found, <code>null</code> otherwise
       */
      public Point getPoint(String name)
      {
        for (int i = 0; i < this.size(); i++)
        {
          if (points[i].pName.equals(name))
            return points[i];
        }
        if (verbosity) pushPrint("***No such point: " + name + "\n");
        return null;
      }
      
      /**
       * Finds a <code>Point</code> by its index in the <code>points</code> array.
       * @param index         index of the <code>Point</code> of interest
       * @return              <code>Point</code> if index is valid, <code>null</code> otherwise
       */
      public Point getPoint(int index)
      {
        if (index >= 0 && index < this.size())
          return points[index];
        else
        {
          if (verbosity) pushPrint("***Index " + index + " not in range\n");
          return null;
        }
      }
      
      /**
       * Get the size of the fourth level of the tree.
       * @return              <code>length</code> property of the <code>points</code> array
       */
      public int size() { return points.length; }
      
      //*****************************************************************************************************************************************************************************
      //***********************************************************************************************************************************************************************Point*
      //*****************************************************************************************************************************************************************************
      /**
       * 
       * Object representing a third level node of the <code>BJaceTree</code>. Contains an array of fourth level objects and methods for executing modes by name or number.
       *
       * @author Conor Freeland, Muninn Group
       * @creation Jan 2013
       *
       */
      public class Point
      {
        public String pName;
        public String type;
        public String ord;
        public Mode[] modes;
        private BComponent thisPoint;
        public boolean valid = true;
        private int added = 0;
        
        /**
         * Constructor for the class.
         * @param name        name of the software point
         * @param ord         ORD pointing to the parent of the software point
         */
        public Point(String name, String type, String ord)
        {
          pName = name;
          this.type = type.toLowerCase();
          this.ord = ord + name;
        }
        
        /**
         * Build method for the fourth level of the tree.
         * @param point       <code>Element</code> containing build data for the lowest level of the tree
         */
        private void build(Element point)
        {
          NodeList list = point.getElementsByTagName("mode");
          modes = new Mode[list.getLength()];

          if (list != null && list.getLength() != 0)
          {
            for (int i = 0; i < list.getLength(); i++)
            {
              Mode mode = new Mode(((Element) list.item(i)).getAttribute("name"),
                                   ((Element) list.item(i)).getAttribute("type"),
                                   ((Element) list.item(i)).getAttribute("number"),
                                   ((Element) list.item(i)).getTextContent());

              if (mode.type.equals("numeric") || mode.type.equals("boolean") || mode.type.equals("enum") || mode.type.equals("virtual"))
              {
                if (this.type.equals(mode.type))
                {
                  if (mode.number <= modes.length)
                  {
                    modes[mode.number - 1] = mode;
                    if (verbosity)
                      pushPrint("    Added " + mode.type + " mode #" + mode.number + ", " + mode.nValue + "\n");
                  }
                }

                else
                {
                  if (verbosity)
                    pushPrint("***Could not add " + mode.type + " mode #" + mode.number + " to " + cName + "/" + pName + ": incorrect mode type\n");
                }
              }

              else
              {
                if (verbosity)
                  pushPrint("***Could not add " + mode.type + " mode #" + mode.number + " to " + cName + "/" + pName + ": invalid mode type\n");
              }
            }
          }
        }
        
        public String createMode(String type, String value)
        {
          String name = "manual_add_" + added;
          Mode newMode = new Mode(name, type, Integer.toString(this.size() + 1), value);
          Mode[] temp = new Mode[this.size() + 1];
          
          for (int i = 0; i < this.size() - 2; i ++)
            temp[i] = modes[i];
          
          temp[this.size()] = newMode;
          modes = temp;
          added++;
          return name;
        }
        
        /**
         * Resolves this <code>Point</code> object into a <code>BComponent</code>.
         * Performs all necessary checks and writes appropriate errors.
         * @return            new point as a <code>BComponent</code> (must be cast back to its specific type by caller), or <code>null</code> if an error occurs
         */
        private BComponent startPoint()
        { 
          if (!thisPoint.isNull())
            return thisPoint;
          
          if (type.equals("numeric"))
          {
            if (isRemote())
            {
              try { thisPoint = (BNumericWritable) BOrd.make(this.ord).resolve(currSession).getComponent(); }
              catch (UnresolvedException e)
              {
                if (verbosity)
                  pushPrint("***Bad controller name:\n" + e.toString() + "\n");
                valid = false;
              }
            }

            else
            {
              try { thisPoint = (BNumericWritable) BOrd.make(this.ord).resolve().getComponent(); }
              catch (UnresolvedException e)
              {
                if (verbosity)
                  pushPrint("***Bad controller name:\n" + e.toString() + "\n");
                valid = false;
              }
            }
          }

          else if (type.equals("boolean"))
          {
            if (isRemote())
            {
              try { thisPoint = (BBooleanWritable) BOrd.make(this.ord).resolve(currSession).getComponent(); }
              catch (UnresolvedException e)
              {
                if (verbosity)
                  pushPrint("***Bad controller name:\n" + e.toString() + "\n");
                valid = false;
              }
            }

            else
            {
              try
              {
                thisPoint = (BBooleanWritable) BOrd.make(this.ord).resolve().getComponent();
              }
              catch (UnresolvedException e)
              {
                if (verbosity)
                  pushPrint("***Bad controller name:\n" + e.toString() + "\n");
                valid = false;
              }
            }
          }
          
          else if (type.equals("enum"))
          {
            if (isRemote())
            {
              try { thisPoint = (BEnumWritable) BOrd.make(this.ord).resolve(currSession).getComponent(); }
              catch (UnresolvedException e)
              {
                if (verbosity)
                  pushPrint("***Bad controller name:\n" + e.toString() + "\n");
                valid = false;
              }
            }

            else
            {
              try { thisPoint = (BEnumWritable) BOrd.make(this.ord).resolve().getComponent(); }
              catch (UnresolvedException e)
              {
                if (verbosity)
                  pushPrint("***Bad controller name:\n" + e.toString() + "\n");
                valid = false;
              }
            }
          }

          else
          {
            if (isRemote())
            {
              try { thisPoint = (BBacnetVirtualProperty) BOrd.make(this.ord).resolve(currSession).getComponent(); }
              catch (UnresolvedException e)
              {
                if (verbosity)
                  pushPrint("***Bad controller name:\n" + e.toString() + "\n");
                valid = false;
              }
            }

            else
            {
              try { thisPoint = (BBacnetVirtualProperty) BOrd.make(this.ord).resolve().getComponent(); }
              catch (UnresolvedException e)
              {
                if (verbosity)
                  pushPrint("***Bad controller name:\n" + e.toString() + "\n");
                valid = false;
              }
            }
          }

          return thisPoint;
        }
        
        /**
         * Resolves this <code>Point</code> object into a usable Baja object, without performing checks.
         * This method should only be used on points already confirmed to be valid.
         * @return            new point as a <code>BComponent</code> (must be cast back to its specific type)
         */
        private BComponent startPointNoCheck()
        {
          if (!thisPoint.isNull())
            return thisPoint;
          
          if (type.equals("numeric"))
          {
            if (isRemote())
            {
              thisPoint = (BNumericWritable) BOrd.make(this.ord).resolve(currSession).getComponent();
            }
            else
              thisPoint = (BNumericWritable) BOrd.make(this.ord).resolve().getComponent();
          }

          else if (type.equals("boolean"))
          {
            if (isRemote())
            {
              thisPoint = (BBooleanWritable) BOrd.make(this.ord).resolve(currSession).getComponent();
            }
            else
              thisPoint = (BBooleanWritable) BOrd.make(this.ord).resolve().getComponent();
          }
          
          else if (type.equals("enum"))
          {
            if (isRemote())
            {
              thisPoint = (BEnumWritable) BOrd.make(this.ord).resolve(currSession).getComponent();
            }
            else
              thisPoint = (BEnumWritable) BOrd.make(this.ord).resolve().getComponent();
          }

          else
          {
            if (isRemote())
            {
              thisPoint = (BBacnetVirtualProperty) BOrd.make(this.ord).resolve(currSession).getComponent(); 
            }
            else
              thisPoint = (BBacnetVirtualProperty) BOrd.make(this.ord).resolve().getComponent();
          }

          return thisPoint;
        }
        
        /**
         * Calls the <code>executeMode(Mode)</code> method with the <code>Mode</code> represented by the parameter.
         * @param name        name of the <code>Mode</code> to be executed
         * @return            return value of the <code>executeMode(Mode)</code> method
         */
        public boolean executeMode(String name) { return executeMode(getMode(name)); }
        
        /**
         * Calls the <code>executeMode(Mode)</code> method with the <code>Mode</code> represented by the parameter.
         * @param index       index of the <code>Mode</code> to be executed
         * @return            return value of the <code>executeMode(Mode)</code> method
         */
        public boolean executeMode(int index) { return executeMode(getMode(index)); }
        
        /**
         * Attempts to resolve the <code>ord</code> property of the parameter into a software point.
         * If this is successful, the point's <code>valid</code> variable is set to <code>true</code> and its fallback property is set to the <code>value</code> property of the parameter.
         * @param mode        <code>Mode</code> whose properties are to be used to resolve and write to the point
         * @return            success/failure determined by whether or not the point is resolved and its fallback is successfully set
         */
        private boolean executeMode(Mode mode)
        {
          if (modes.length == 0)
          {
            valid = false;
            if (verbosity)
              pushPrint("***No valid modes on point " + cName + "/" + pName + "\n");
            return false;
          }

          if (mode == null)
          {
            if (verbosity)
              pushPrint("***Invalid mode requested on point " + cName + "/" + pName + "\n");
            return false;
          }

          if (type.equals("numeric"))
          {
            BNumericWritable rPoint = (BNumericWritable) startPoint();
            
            if (rPoint != null)
            {
              rPoint.lease();
              rPoint.setFallback((BStatusNumeric) BStatusNumeric.make(BInteger.make(mode.nValue)));

              valid = true;
              if (verbosity)
                pushPrint("Point " + cName + "/" + pName + " accessed, attempting to write " + mode.nValue + "\n");
              return true;
            }

            else
            {
              valid = false;
              if (verbosity)
                pushPrint("***Could not access point: \n" + "ip:" + address + ":|" + ord + "\n");
              return false;
            }
          }

          else if (type.equals("boolean"))
          {
            BBooleanWritable rPoint = (BBooleanWritable) startPoint();
            
            if (rPoint != null)
            {
              rPoint.lease();
              rPoint.setFallback((BStatusBoolean) BStatusBoolean.make(BBoolean.make(mode.bValue)));

              valid = true;
              if (verbosity)
                pushPrint("Point " + cName + "/" + pName + " accessed, attempting to write " + mode.bValue + "\n");
              return true;
            }

            else
            {
              valid = false;
              if (verbosity)
                pushPrint("***Could not access point: \n" + "ip:" + address + ":|" + ord + "\n");
              return false;
            }
          }
          
          else if (type.equals("enum"))
          {
            BEnumWritable rPoint = (BEnumWritable) startPoint();
            
            if (rPoint != null)
            {
              rPoint.lease();
              rPoint.getFallback().setValueValue(BDynamicEnum.make(mode.nValue));
              
              valid = true;
              if (verbosity)
                pushPrint("Point " + cName + "/" + pName + " accessed, attempting to write " + mode.bValue + "\n");
              return true;
            }

            else
            {
              valid = false;
              if (verbosity)
                pushPrint("***Could not access point: \n" + "ip:" + address + ":|" + ord + "\n");
              return false;
            }
          }

          else
          {
            BBacnetVirtualProperty rPoint = (BBacnetVirtualProperty) startPoint();
            
            if (rPoint != null)
            {
              rPoint.lease();
              if (rPoint.getParent().getName().contains("analog"))
              {
                rPoint.setValue(BDouble.make(mode.nValue));

                valid = true;
                if (verbosity)
                  pushPrint("Point " + cName + "/" + pName + " accessed, attempting to write " + mode.nValue + "\n");
                return true;
              }

              else if (rPoint.getParent().getName().contains("multiState"))
              {
                rPoint.setValue(BBacnetUnsigned.make((long) mode.nValue));

                valid = true;
                if (verbosity)
                  pushPrint("Point " + cName + "/" + pName + " accessed, attempting to write " + mode.nValue + "\n");
                return true;
              }

              else
              {
                rPoint.setValue(BBoolean.make(mode.bValue));

                valid = true;
                if (verbosity)
                  pushPrint("Point " + cName + "/" + pName + " accessed, attempting to write " + mode.bValue + "\n");
                return true;
              }
            }

            else
            {
              valid = false;
              if (verbosity)
                pushPrint("***Could not access point: \n" + "ip:" + address + ":|" + ord + "\n");
              return false;
            }
          }
        }
        
        /**
         * Calls the <code>checkPoint(Mode)</code> method with the <code>Mode</code> represented by the parameter.
         * @param index       name of the <code>Mode</code> to be checked against
         * @return            return value of the <code>checkPoint(Mode)</code> method
         */
        public boolean checkPoint(String name) { return checkPoint(getMode(name)); }
        
        /**
         * Calls the <code>checkPoint(Mode)</code> method with the <code>Mode</code> represented by the parameter.
         * @param index       index of the <code>Mode</code> to be checked against
         * @return            return value of the <code>checkPoint(Mode)</code> method
         */
        public boolean checkPoint(int index) { return checkPoint(getMode(index)); }
        
        /**
         * Verifies that the attempted write to the point was successful, if the point's <code>valid</code> property is <code>true</code>.
         * @param mode        <code>Mode</code> whose properties are to be used to check that the write was successful
         * @return            success/failure determined by whether or not the point's <code>out</code> property matches its <code>fallback</code> property.
         */
        private boolean checkPoint(Mode mode)
        {
          if (mode == null)
            return false;

          if (type.equals("numeric"))
          {
            if (!valid)
              return false;

            else
            {
              BNumericWritable rPoint = (BNumericWritable) startPointNoCheck();

              rPoint.lease();
              String status = rPoint.getOut().getStatus().toString();
              if (rPoint.getOut().getValue() == mode.nValue && status.contains("ok"))
              {
                if (verbosity)
                  pushPrint("Value " + mode.nValue + " written to " + cName + "/" + pName + "\n");
                return true;
              }

              else
              {
                if (verbosity)
                  pushPrint("***Failed to write to " + cName + "/" + pName + ", point may be down\n" + "ip:" + address + ":|" + ord + "\n");
                return false;
              }
            }
          }

          else if (type.equals("boolean"))
          {
            if (!valid)
              return false;

            else
            {
              BBooleanWritable rPoint = (BBooleanWritable) startPointNoCheck();

              rPoint.lease();
              String status = rPoint.getOut().getStatus().toString();
              if (rPoint.getOut().getValue() == mode.bValue && status.contains("ok"))
              {
                if (verbosity)
                  pushPrint("Value " + mode.bValue + " written to " + cName + "/" + pName + "\n");
                return true;
              }

              else
              {
                if (verbosity)
                  pushPrint("***Failed to write to " + cName + "/" + pName + ", point may be down\n" + "ip:" + address + ":|" + ord + "\n");
                return false;
              }
            }
          }
          
          else if (type.equals("enum"))
          {
            if (!valid)
              return false;

            else
            {
              BEnumWritable rPoint = (BEnumWritable) startPointNoCheck();

              rPoint.lease();
              String status = rPoint.getOut().getStatus().toString();
              if (rPoint.getOut().getValue().getOrdinal() == mode.nValue && status.contains("ok"))
              {
                if (verbosity)
                  pushPrint("Value " + mode.nValue + " written to " + cName + "/" + pName + "\n");
                return true;
              }

              else
              {
                if (verbosity)
                  pushPrint("***Failed to write to " + cName + "/" + pName + ", point may be down\n" + "ip:" + address + ":|" + ord + "\n");
                return false;
              }
            }
          }

          else
          {
            if (!valid)
              return false;
            else
            {
              BBacnetVirtualProperty rPoint = (BBacnetVirtualProperty) startPointNoCheck();
              
              rPoint.lease();
              if (rPoint.getParent().getName().contains("analog") && rPoint.getValue().equals(BDouble.make(mode.nValue)))
              {
                if (verbosity)
                  pushPrint("Value " + mode.nValue + " written to " + cName + "/" + pName + "\n");
                return true;
              }
              
              else if (rPoint.getParent().getName().contains("multiState") && rPoint.getValue().equals(BBacnetUnsigned.make((long) mode.nValue)))
              {
                if (verbosity)
                  pushPrint("Value " + mode.nValue + " written to " + cName + "/" + pName + "\n");
                return true;
              }
              
              else if (rPoint.getParent().getName().contains("binary") && rPoint.getValue().equals(BBoolean.make(mode.bValue)))
              {
                if (verbosity)
                  pushPrint("Value " + mode.bValue + " written to " + cName + "/" + pName + "\n");
                return true;
              }
              
              else
              {
                if (verbosity)
                  pushPrint("***Failed to write to " + cName + "/" + pName + ", point may be down\n" + "ip:" + address + ":|" + ord + "\n");
                return false;
              }
            }
          }
        }
        
        /**
         * Finds a <code>Mode</code> by its <code>mName</code> property.
         * @param name        name of the <code>Mode</code> of interest
         * @return            <code>Mode</code> if a match is found, <code>null</code> otherwise
         */
        public Mode getMode(String name)
        {
          for (int i = 0; i < this.size(); i++)
          {
            if (modes[i].mName.equals(name))
              return modes[i];
          }
          if (verbosity)
            pushPrint("***No such mode: " + name + "\n");
          return null;
        }
        
        /**
         * Finds a <code>Mode</code> by its index in the <code>points</code> array.
         * @param index       index of the <code>Mode</code> of interest
         * @return            <code>Mode</code> if index is valid, <code>null</code> otherwise
         */
        public Mode getMode(int index)
        {
          if (index > 0 && index <= this.size())
            return modes[index - 1];
          else
          {
            if (verbosity)
              pushPrint("***Index " + index + " not in range\n");
            return null;
          }
        }
        
        /**
         * Get the size of the fifth level of the tree.
         * @return            <code>length</code> property of the <code>modes</code> array
         */
        public int size() { return modes.length; }

        //***************************************************************************************************************************************************************************
        //**********************************************************************************************************************************************************************Mode*
        //***************************************************************************************************************************************************************************
        /**
         * 
         * Object containing the information for execution on <code>Points</code>.
         *
         * @author Conor Freeland, Muninn Group
         * @creation Jan 2013
         *
         */
        public class Mode
        {
          public String mName = null;
          public String type = null;
          public int number = 0;
          public int nValue = 0;
          public boolean bValue = false;
          
          /**
           * Constructor for the class.
           * @param name      name of the <code>Mode</code>
           * @param number    number of the <code>Mode</code>
           * @param value     value to be used when executing the <code>Mode</code>
           */
          public Mode(String name, String type, String number, String value)
          {
            this.mName = name;
            this.type = type.toLowerCase();
            this.number = Integer.parseInt(number);
            if (!type.equals("boolean"))
              nValue = Integer.parseInt(value);
            else
              bValue = value.toLowerCase().equals("true");
          }
          
          /**
           * Setter for the <code>mName</code> property of this mode.
           * @param name      new <code>mName</code> value
           */
          public void setName(String name) { mName = name; }
          
          /**
           * Setter for the <code>type</code> property of this mode.
           * @param type      new <code>type</code> value
           */
          public void setType(String type)
          {
            if (type.equals("numeric") || type.equals("boolean") || !type.equals("virtual"))
              this.type = type;
          }
          
          /**
           * Setter for the <code>nValue</code> property of this mode.
           * @param val       new <code>nValue</code> value
           */
          public void setNValue(int val) { nValue = val; }
          
          /**
           * Setter for the <code>bValue</code> property of this mode.
           * @param val       new <code>bValue</code> value
           */
          public void setBValue(boolean val) { bValue = val; }
        }
      }
    }
  }
  
  public static final Type TYPE = Sys.loadType(BJaceTree.class);
  public Type getType() { return TYPE; }
}
